package com.uzhie.web.service;

import com.alibaba.fastjson.JSONObject;
import com.uzhie.web.dao.CatalogDAO;
import com.uzhie.web.dao.UserDAO;
import com.uzhie.web.dao.VideoDAO;
import com.uzhie.web.dao.VideoMonitorReportDAO;
import com.uzhie.exception.MonitorException;
import com.uzhie.exception.UserException;
import com.uzhie.jt808.jt1078.entity.JT_9101;
import com.uzhie.jt808.jt1078.entity.JT_9102;
import com.uzhie.jt808.JT808Constant;
import com.uzhie.jt808.service.JT808ServiceImpl;
import com.uzhie.media.MediaConstant;
import com.uzhie.media.service.MediaPostServiceImpl;
import com.uzhie.media.task.MediaOnLineNumTask;
import com.uzhie.web.module.Catalog;
import com.uzhie.web.module.User;
import com.uzhie.web.module.Video;
import com.uzhie.web.module.VideoMonitorReport;
import com.uzhie.util.ConstantKit;
import com.uzhie.util.RedisCacheManager;
import com.uzhie.util.TreeBuildUtil;
import com.uzhie.util.TreeUtil;
import io.netty.buffer.ByteBufUtil;
import org.apache.log4j.Logger;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 直播监控服务对象
 * Created by lilongfei on 2018/7/24.
 */
@Service
public class MonitoringService {

    @Autowired(required = false)
    private JT808ServiceImpl jt808Service;
    @Autowired(required = false)
    private CatalogDAO catalogDAO;
    @Autowired(required = false)
    private UserDAO userDAO;
    @Autowired(required = false)
    private VideoDAO videoDAO;
    @Autowired(required = false)
    private VideoMonitorReportDAO videoMonitorReportDAO;
    @Autowired(required = false)
    private MediaPostServiceImpl<Integer> mediaPostService;
    @Autowired(required = false)
    RedisCacheManager<VideoMonitorReport> redisCacheManager;

    private Logger logger = Logger.getLogger(this.getClass());

    //音视频数据类型 1 视频,2 双向对讲,3 监听,4 中心广播,5 透传
    private final List<Integer> types;
    //0 主码流,1 子码流
    private final List<Integer> streams;
    //关闭类型 0 关闭音视频数据,1 只关闭音频  2 只关闭视频
    private final List<Integer> orders;
    //控制类型 0 关闭音视频传输,1 切换码流, 2 暂停传输,3 恢复传输,4 关闭双向对讲
    private final List<Integer> controls;

    {
        types = Arrays.asList(1, 2, 3, 4, 5);
        streams = Arrays.asList(0, 1);
        orders = Arrays.asList(0, 1, 2);
        controls = Arrays.asList(0, 1, 2, 3, 4);
    }


    /**
     * 通过用户id查询该用户可管理的所有车辆
     *
     * @param userId
     * @return
     */
    public List<Catalog> queryListByUserId(@NotEmpty(message = UserException.Status.ID_ISNULL) String userId) throws MonitorException {

        User user = userDAO.selectByPrimaryKey(userId);
        if (user == null) throw new MonitorException(MonitorException.Status.USER_ERROR);
        //用户关联的权限目录
        List<Catalog> nodes = catalogDAO.selectCatalogByUserId(userId);
        //通过部门id全部的权限目录
        List<Catalog> origins = catalogDAO.selectCatalogByUserDepart(user.getDepartmentId());
        if (nodes != null && nodes.size() > 0) {
            //迭代出用户关联的权限目录的全部上级目录
            List<Catalog> result = new TreeBuildUtil(origins, nodes).filter();
            //通过目录list构建目录树
            result = new TreeUtil(result, jt808Service).buildCatalogTree();
            return result;
        } else
            throw new MonitorException(MonitorException.Status.NODE_ERROR);
    }

    /**
     * 下达开始监控指令
     *
     * @param vehicleNumber 车辆关联的手机号
     * @param ip            流媒体服务器ip
     * @param tcpPort       流媒体tcp端口
     * @param udpPort       流媒体udp端口
     * @param channel       逻辑通道号
     * @param stream        主码流,子码流
     * @param type          音视频数据类型 1 视频,2 双向对讲,3 监听,4 中心广播,5 透传
     */
    public String startOrder(@NotEmpty(message = MonitorException.Status.TEL_ERROR) String vehicleNumber,
                             @NotEmpty(message = MonitorException.Status.IP_ERROR) String ip,
                             String tcpPort, String udpPort, int channel, int stream, int type) throws MonitorException {
        System.out.println(Thread.currentThread().getId());

        if (!types.contains(type)) throw new MonitorException(MonitorException.Status.TYPE_ERROR);
        if (!streams.contains(stream)) throw new MonitorException(MonitorException.Status.STREAM_ERROR);

        //播放器客户端监控
        VideoMonitorReport videoMonitorReport = new VideoMonitorReport();
        videoMonitorReport.setVehicleNumber(vehicleNumber);
        videoMonitorReport.setChannelNumber(channel + "");
        videoMonitorReport.setMonitorType("直播");
        videoMonitorReport.setBitStream(stream == 0 ? "主码流" : "子码流");
        videoMonitorReport.setBeginTime(new Date());
        videoMonitorReport.setBrowserType("IE11浏览器");

        redisCacheManager.set(vehicleNumber, videoMonitorReport);

        //下发直播监控指令
        JSONObject body = new JSONObject();
        body.put("channelNumber", channel);
        body.put("simNo", vehicleNumber);
        body.put("playType", 1);
        JSONObject object = new JSONObject();
        object.put("playType", 0);
        /** try {
         //            JSONArray array = mediaPostService.postWithResult(MediaConstant.MSG_ID.PLA_REQ_CHANNEL_TYPE_NUMBER, object, MediaChannelTypeOnLineNumTask.class, JSONArray.class);
         //            logger.info("得到总共的通道列表是：" + array);
         Integer count = mediaPostService.postWithResult(MediaConstant.MSG_ID.PLA_REQ_ONLINE_CHANNEL, body, MediaOnLineNumTask.class, Integer.class);
         logger.info("得到的通道数是：" + count);
         if (count == null) {
         throw new MonitorException(MonitorException.Status.MEDIA_ERROR);
         } else if (count.intValue() > 0) {
         logger.warn("设备:" + vehicleNumber + "  通道 :" + channel + "  视频数据通道已连接,无需下发推送指令");
         return "该设备视频数据通道已连接,无需下发推送指令";
         }
         } catch (Exception e) {
         throw new MonitorException(MonitorException.Status.MEDIA_ERROR);
         }**/

        try {
            short s_tcp = Short.parseShort(tcpPort);
            short s_ucp = Short.parseShort(udpPort);
            JT_9101 order = new JT_9101(channel, stream, type, s_tcp, s_ucp, ip);
            //请求执行下达
            byte[] result = jt808Service.postWithResult(JT808Constant.MSG_ID.PLA_REQ_MONITOR, vehicleNumber, order.WriteToBytes(), byte[].class);
            logger.info("设备:" + vehicleNumber + "  通道 :" + channel + " 实时监控指令下发成功 终端响应结果为：" + ByteBufUtil.hexDump(result));
            return "指令下发成功";
        } catch (NumberFormatException e) {
            throw new MonitorException(MonitorException.Status.PORT_ERROR);
        } catch (NullPointerException e) {
            throw new MonitorException(MonitorException.Status.NOT_ONLINE);
        }
    }


    /**
     * 下达监控控制指令
     *
     * @param vehicleNumber 车载sim卡号
     * @param channel       逻辑通道号
     * @param order         命令内容,关闭视频还是音频 0 关闭音视频传输 1切换码流 2暂停该通道所有推送  3恢复流推送 4 关闭双向对讲
     * @param stream        码流 0 主码流 1 子码流
     * @param control       操作的控制类型  0关闭所有音视频 1 只关闭音频 2 只关闭视频
     * @return true 发送成功  false 发送失败
     * @throws MonitorException 参数异常指令
     */
    public String controlOrder(@NotEmpty(message = MonitorException.Status.TEL_ERROR) String vehicleNumber,
                               int channel, int order, int stream, int control) throws MonitorException {


        if (!orders.contains(order)) throw new MonitorException(MonitorException.Status.ORDER_ERROR);
        if (!streams.contains(stream)) throw new MonitorException(MonitorException.Status.STREAM_ERROR);
        if (!controls.contains(control)) throw new MonitorException(MonitorException.Status.CONTROL_ERROR);
        //存储客户端指令
//        VideoMonitorReport videoMonitorReport = redisCacheManager.get(vehicleNumber);
//        redisCacheManager.del(vehicleNumber);
//        videoMonitorReport.setEndTime(new Date());
//        videoMonitorReportDAO.insert(videoMonitorReport);

        //拼装控制指令
        JSONObject body = new JSONObject();
        body.put("channelNumber", channel);
        body.put("simNo", vehicleNumber);
        body.put("playType", 1);
        JSONObject object = new JSONObject();
        object.put("playType", 0);
        try {
//            JSONArray array = mediaPostService.postWithResult(MediaConstant.MSG_ID.PLA_REQ_CHANNEL_TYPE_NUMBER, object, MediaChannelTypeOnLineNumTask.class, JSONArray.class);
//            logger.info("得到总共的通道列表是：" + array);
            Integer result = mediaPostService.postWithResult(MediaConstant.MSG_ID.PLA_REQ_ONLINE_CHANNEL, body, MediaOnLineNumTask.class, Integer.class);
            logger.info("设备:" + vehicleNumber + "  通道 :" + channel + "  观看人数为：" + result);
//                Integer result = mediaPostService.postWithResult(MediaConstant.MSG_ID.PLA_REQ_ONLINE_CHANNEL, body);
            if (0 == order && result != null && 1 < result) {
                logger.warn("设备:" + vehicleNumber + "  通道 :" + channel + "  视频存在多人观看,无需下发关闭指令");
                return "该通道视频存在多人观看,无需下发关闭指令";
            }
        } catch (Exception e) {
            logger.error("流媒体服务查询通道异常！");
            throw new MonitorException(MonitorException.Status.MEDIA_ERROR);
        }

        try {
            JT_9102 m_order = new JT_9102(channel, order, control, stream);
            //请求执行下达
            byte[] result = jt808Service.postWithResult(JT808Constant.MSG_ID.PLA_REQ_MONITOR_CONTROL, vehicleNumber, m_order.WriteToBytes(), byte[].class);
            logger.info("设备:" + vehicleNumber + "  通道 :" + channel + "  指令:" + control + "  下发成功 终端响应结果为：" + ByteBufUtil.hexDump(result));
            return "指令下发成功";
        } catch (NullPointerException e) {
            logger.error("808服务下发指令异常！");
            throw new MonitorException(MonitorException.Status.NOT_ONLINE);
        }
    }

    /**
     * 保存新的视频
     *
     * @param obj
     */
    public void addVideo(JSONObject obj) {
        try {
            Video video = new Video();
            video.setChannel(obj.getInteger("channelNumber"));
            video.setVehicleNumber(obj.getString("simNo"));
            video.setBeginTime(obj.getDate("beginTime"));
            video.setEndTime(obj.getDate("endTime"));
            video.setSize(obj.getDouble("size"));
            video.setDuration(obj.getDouble("duration"));
            video.setType(obj.getString("type"));
            video.setStoragePosition(obj.getString("storagePosition"));
            video.setRecordTime(obj.getDate("recordTime"));
            video.setStatus(ConstantKit.STATUS.IS_AVAILABLE);
            videoDAO.insert(video);
        } catch (Exception e) {
            logger.error("保存视频错误", e);
        }
    }

    /**
     * 前端播放状态保持
     *
     * @param status   视频状态
     * @param simNo    sim卡号
     * @param channel  通道号
     * @param playType 播放状态 1 直播 2复播
     */

    public void PlayerKeepLive(String status, String simNo, Integer channel, Integer playType) throws MonitorException {
        try {
            //下发直播监控指令
            JSONObject body = new JSONObject();
            body.put("status", status);
            body.put("simNo", simNo);
            body.put("channelNumber", channel);
            body.put("playType", playType);
            mediaPostService.post(MediaConstant.MSG_ID.PLA_REQ_PLAY_STATUS_KEEP, body);
        } catch (Exception e) {
            logger.error(MonitorException.Status.MEDIA_ERROR, e);
            throw new MonitorException(MonitorException.Status.MEDIA_ERROR);
        }
    }

}
